package com.pb.infra.oth.handler;

import com.pb.infra.oth.entity.common.Result;
import com.pb.infra.oth.exception.AppAuthException;
import com.pb.infra.oth.exception.BizException;
import com.pb.infra.oth.exception.ErrorCode;
import com.pb.infra.oth.exception.FrameworkException;
import com.pb.infra.oth.util.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;

/**
 * 异常处理
 */
@RestControllerAdvice(basePackages = "com.pb")
@Slf4j
public class RestExceptionHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public Result handlerArgException(MethodArgumentNotValidException e, HttpServletRequest request) {
        log.error(request.getRequestURL().toString(), e);
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(item -> item.getField() + "is required")
                .collect(Collectors.joining(", "));
        return Result.error(ErrorCode.INVALID_ARG, message);
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({IllegalArgumentException.class})
    public Result handleIllegaArgException(IllegalArgumentException e, HttpServletRequest request) {
        log.error(request.getRequestURL().toString(), e);
        return Result.error(ErrorCode.INVALID_ARG, e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({BizException.class})
    public Result handleBizException(BizException e, HttpServletRequest request) {
        log.error(request.getRequestURL().toString(), e);
        return Result.error(ErrorCode.buildCode(ErrorCode.ErrorType.BIZ, ErrorCode.ErrorLevel.WARN, e.getCode()), e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({AppAuthException.class})
    public Result handleAppAuthException(AppAuthException e, HttpServletRequest request) {
        log.error("AppAuthError: " + LogUtil.buildMessage(e.getMessage(), e.getParams()));
        return Result.error(ErrorCode.buildCode(ErrorCode.ErrorType.BIZ, ErrorCode.ErrorLevel.WARN, e.getCode()), e.getMessage());
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler({FrameworkException.class})
    public Result handleFrameException(FrameworkException e, HttpServletRequest request) {
        log.error(request.getRequestURL().toString(), e);
        return Result.error(ErrorCode.buildCode(ErrorCode.ErrorType.SYSTEM, ErrorCode.ErrorLevel.ERROR, "F001"), e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({RuntimeException.class})
    public Result handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        log.error(request.getRequestURL().toString(), e);
        return Result.error(ErrorCode.buildCode(ErrorCode.ErrorType.SYSTEM, ErrorCode.ErrorLevel.WARN, "S001"), "系统后端异常，请联系管理员");
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler({Exception.class})
    public Result handleException(Exception e, HttpServletRequest request) {
        log.error(request.getRequestURL().toString(), e);
        return Result.error(ErrorCode.buildCode(ErrorCode.ErrorType.SYSTEM, ErrorCode.ErrorLevel.ERROR, "E001"), "系统后端异常，请联系管理员");
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler({Error.class})
    public Result handleError(Error e, HttpServletRequest request) {
        log.error(request.getRequestURL().toString(), e);
        return Result.error(ErrorCode.buildCode(ErrorCode.ErrorType.THIRD, ErrorCode.ErrorLevel.ERROR, "3001"), "系统后端异常，请联系管理员");
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler({Throwable.class})
    public Result handleThrowable(Throwable e, HttpServletRequest request) {
        log.error(request.getRequestURL().toString(), e);
        return Result.error(ErrorCode.buildCode(ErrorCode.ErrorType.SYSTEM, ErrorCode.ErrorLevel.ERROR, "U001"), "系统后端异常，请联系管理员");
    }

}
